package com.jerome.election.server.paxos;

import com.jerome.election.http.HttpConstant;
import com.jerome.election.server.ContextUtil;
import com.jerome.election.storage.ExpiringMap;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Jerome
 * @date 2023/10/19
 */
public class Learner {
    /**
     * 已经接受的提案
     */
    private Map<Integer, String> acceptedValues = new HashMap<>();
    /**
     * 待选提案
     */
    private ExpiringMap<Integer, Integer> quasiProposals = new ExpiringMap<>(15000);

    public Map<Integer, String> getAcceptedValues() {
        return acceptedValues;
    }

    /**
     * 学习提案
     *
     * @param paxosMessage 提案信息
     * @author Jerome
     * @date 2023/10/19 15:51
     */
    public synchronized boolean learnProposal(PaxosMessage paxosMessage) throws IOException {
        //学习 ACCEPT 结果
        if(ContextUtil.getLeaner().getAcceptedValues().containsKey(paxosMessage.getProposalNumber())){
            //已经学习的提案跳过
            return false;
        }
        //进行投票
        Integer count = ContextUtil.getLeaner().setQuasiProposalsVotes(paxosMessage.getProposalNumber());
        //选票过半
        if (count >= ContextUtil.getMajorNum()) {
            //接受者处学习已接受的值
            ContextUtil.getLeaner().getAcceptedValues().put(paxosMessage.getProposalNumber(), paxosMessage.getProposalValue());
            //记录学习值
            ContextUtil.getLogger().write(paxosMessage.toString() + HttpConstant.LINE_SEPARATOR);
            return true;
        }
        return false;
    }

    /**
     * 候选提案获取增加选票
     *
     * @return
     */
    private Integer setQuasiProposalsVotes(int proposalNumber) {
        Integer count = quasiProposals.get(proposalNumber);
        if (count == null) {
            count = 1;
        } else {
            count++;
        }
        quasiProposals.put(proposalNumber, count);
        return count;
    }
}
